#include "widget.h"
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSpacerItem>
#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QDateTime>
#include <QRandomGenerator>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    this->setStyleSheet("font: 18px Microsoft YaHei");
    this->setWindowTitle("语法高亮");
    this->initLayout();

    _codeTimer = new QTimer(this);
    connect(_codeTimer, &QTimer::timeout, this, &Widget::onCodeTimerTimeout);

    _jsonTimer = new QTimer(this);
    connect(_jsonTimer, &QTimer::timeout, this, &Widget::onJsonTimerTimeout);

    _deviceTimer = new QTimer(this);
    connect(_deviceTimer, &QTimer::timeout, this, &Widget::onDeviceTimerTimeout);

    _openCodeBtn->click();
    _openJsonBtn->click();


    connect(_codePreview, &QPushButton::clicked, [this]() {
        QString fileName = QFileDialog::getOpenFileName(this, "文件列表", QDir::currentPath(), "Text files (*.h *.cpp)");
        if (fileName.size()) {
            this->loadFile(_codeEdit, fileName);
        }
    });

    connect(_jsonPreview, &QPushButton::clicked, [this]() {
        QString fileName = QFileDialog::getOpenFileName(this, "文件列表", QDir::currentPath(), "Text files (*.json)");
        if (fileName.size()) {
            this->loadFile(_jsonEdit, fileName);
        }
    });

    connect(_startRecvBtn, &QPushButton::clicked, [this]() {
        if (_deviceTimer->isActive()) {
            _startRecvBtn->setText("开始接收");
            _deviceTimer->stop();
        } else {
            _startRecvBtn->setText("停止接收");
            _deviceTimer->start(800);
        }
    });

    connect(_clearDataBtn, &QPushButton::clicked, [this]() {
        _deviceEdit->clear();
    });
}

Widget::~Widget() {

}

void Widget::initLayout()
{
    QGridLayout* gridLayout = new QGridLayout(this);
    gridLayout->setContentsMargins(10, 10, 10, 10);
    gridLayout->setSpacing(20);

    // 1.代码高亮
    QVBoxLayout* codeLayout = new QVBoxLayout();
    codeLayout->setContentsMargins(0, 0, 0, 0);
    codeLayout->setSpacing(5);
    gridLayout->addLayout(codeLayout, 0, 0);

    // 1.1 标题
    QHBoxLayout* codeTitleLayout = new QHBoxLayout();
    codeTitleLayout->setContentsMargins(0, 0, 0, 0);
    codeTitleLayout->setSpacing(0);
    codeLayout->addLayout(codeTitleLayout);

    QCheckBox* chkCode = new QCheckBox(this);
    chkCode->setText("代码高亮");
    codeTitleLayout->addWidget(chkCode);

    QSpacerItem* sp1 = new QSpacerItem(20, 8, QSizePolicy::Expanding, QSizePolicy::Fixed);
    codeTitleLayout->addItem(sp1);

    _openCodeBtn = new QRadioButton(this);
    _openCodeBtn->setText("打开文件");
    codeTitleLayout->addWidget(_openCodeBtn);

    _codePreview = new QPushButton(this);
    _codePreview->setText("浏览...");
    codeTitleLayout->addWidget(_codePreview);

    QSpacerItem* sp2 = new QSpacerItem(64, 8, QSizePolicy::Fixed, QSizePolicy::Fixed);
    codeTitleLayout->addItem(sp2);

    _keyboardCodeBtn = new QRadioButton(this);
    _keyboardCodeBtn->setText("模拟键盘输入");
    codeTitleLayout->addWidget(_keyboardCodeBtn);

    _codeBtnGroup = new QButtonGroup(this);
    _codeBtnGroup->addButton(_openCodeBtn, 0);
    _codeBtnGroup->addButton(_keyboardCodeBtn, 1);

    connect(_openCodeBtn, &QRadioButton::clicked, this, &Widget::onCodeRadioButtonClick);
    connect(_keyboardCodeBtn, &QRadioButton::clicked, this, &Widget::onCodeRadioButtonClick);

    // 1.2 主体区域
    _codeEdit = new QTextEdit(this);
    codeLayout->addWidget(_codeEdit);


    // 2.Json高亮
    QVBoxLayout* jsonLayout = new QVBoxLayout();
    jsonLayout->setContentsMargins(0, 0, 0, 0);
    jsonLayout->setSpacing(5);
    gridLayout->addLayout(jsonLayout, 1, 0);

    // 2.1 标题
    QHBoxLayout* jsonTitleLayout = new QHBoxLayout();
    jsonTitleLayout->setContentsMargins(0, 0, 0, 0);
    jsonTitleLayout->setSpacing(0);
    jsonLayout->addLayout(jsonTitleLayout);

    QCheckBox* chkJson = new QCheckBox(this);
    chkJson->setText("Json高亮");
    jsonTitleLayout->addWidget(chkJson);

    QSpacerItem* sp3 = new QSpacerItem(20, 8, QSizePolicy::Expanding, QSizePolicy::Fixed);
    jsonTitleLayout->addItem(sp3);

    _openJsonBtn = new QRadioButton(this);
    _openJsonBtn->setText("打开文件");
    jsonTitleLayout->addWidget(_openJsonBtn);

    _jsonPreview = new QPushButton(this);
    _jsonPreview->setText("浏览...");
    jsonTitleLayout->addWidget(_jsonPreview);

    QSpacerItem* sp4 = new QSpacerItem(64, 8, QSizePolicy::Fixed, QSizePolicy::Fixed);
    jsonTitleLayout->addItem(sp4);

    _keyboardJsonBtn = new QRadioButton(this);
    _keyboardJsonBtn->setText("模拟键盘输入");
    jsonTitleLayout->addWidget(_keyboardJsonBtn);

    _jsonBtnGroup = new QButtonGroup(this);
    _jsonBtnGroup->addButton(_openJsonBtn, 0);
    _jsonBtnGroup->addButton(_keyboardJsonBtn, 1);

    connect(_openJsonBtn, &QRadioButton::clicked, this, &Widget::onJsonRadioButtonClick);
    connect(_keyboardJsonBtn, &QRadioButton::clicked, this, &Widget::onJsonRadioButtonClick);

    // 2.2 主体区域
    _jsonEdit = new QTextEdit(this);
    jsonLayout->addWidget(_jsonEdit);

    // 3.下位机高亮
    QVBoxLayout* deviceLayout = new QVBoxLayout();
    deviceLayout->setContentsMargins(0, 0, 0, 0);
    deviceLayout->setSpacing(5);
    gridLayout->addLayout(deviceLayout, 0, 1, 2, 1);

    // 3.1 标题
    QHBoxLayout* deviceTitleLayout = new QHBoxLayout();
    deviceTitleLayout->setContentsMargins(0, 0, 0, 0);
    deviceTitleLayout->setSpacing(0);
    deviceLayout->addLayout(deviceTitleLayout);

    QCheckBox* chkDevice = new QCheckBox(this);
    chkDevice->setText("下位机高亮");
    deviceTitleLayout->addWidget(chkDevice);

    QSpacerItem* sp5 = new QSpacerItem(20, 8, QSizePolicy::Expanding, QSizePolicy::Fixed);
    deviceTitleLayout->addItem(sp5);

    _startRecvBtn = new QPushButton(this);
    _startRecvBtn->setText("开始接收");
    deviceTitleLayout->addWidget(_startRecvBtn);

    QSpacerItem* sp6 = new QSpacerItem(8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed);
    deviceTitleLayout->addItem(sp6);

    _clearDataBtn = new QPushButton(this);
    _clearDataBtn->setText("清空数据");
    deviceTitleLayout->addWidget(_clearDataBtn);

    // 3.2 主体区域
    _deviceEdit = new QTextEdit(this);
    _deviceEdit->document()->setMaximumBlockCount(100);
    _deviceEdit->setReadOnly(true);
    _deviceEdit->setStyleSheet("font: 18px Consolas");
    deviceLayout->addWidget(_deviceEdit);

    connect(chkCode, &QCheckBox::stateChanged, [=]() {
        if (chkCode->isChecked()) {
            _codeHighlighter = new CodeSyntaxHighLight(_codeEdit->document());
        } else {
            _codeHighlighter->deleteLater();
            _codeHighlighter = nullptr;
        }
    });

    connect(chkJson, &QCheckBox::stateChanged, [=]() {
        if (chkJson->isChecked()) {
            _jsonHighlighter = new JsonSyntaxHighlight(_jsonEdit->document());
        } else {
            _jsonHighlighter->deleteLater();
            _jsonHighlighter = nullptr;
        }
    });

    connect(chkDevice, &QCheckBox::stateChanged, [=]() {
        if (chkDevice->isChecked()) {
            _deviceHighlighter = new DeviceSyntaxHighlight(_deviceEdit->document());
        } else {
            _deviceHighlighter->deleteLater();
            _deviceHighlighter = nullptr;
        }
    });
}

void Widget::loadFile(QTextEdit* textEdit, const QString& fileName)
{
    textEdit->clear();
    QFile file(fileName);
    if (file.open(QIODeviceBase::ReadOnly)) {
        QTextStream in(&file);
        while (!in.atEnd()) {
            textEdit->append(in.readLine());
        }
        file.close();
    } else {
        QMessageBox::warning(this, "warning", "打开文件错误", QMessageBox::Ok);
    }
}

void Widget::onCodeRadioButtonClick()
{
    _codeEdit->clear();
    int checkId = _codeBtnGroup->checkedId();
    if (checkId == 0) {
        _codePreview->setEnabled(true);
        _codeTimer->stop();
        _codeString.clear();
    } else {
        _codePreview->setEnabled(false);
        QFile file(":/highlight.cpp");
        if (file.open(QIODevice::ReadOnly)) {
            _codeString = file.readAll();
        }
        _codeTimer->start(30);
    }
}

void Widget::onJsonRadioButtonClick()
{
    _jsonEdit->clear();
    int checkId = _jsonBtnGroup->checkedId();
    if (checkId == 0) {
        _jsonPreview->setEnabled(true);
        _jsonTimer->stop();
        _jsonString.clear();
    } else {
        _jsonPreview->setEnabled(false);
        QFile file(":/highlight.json");
        if (file.open(QIODevice::ReadOnly)) {
            _jsonString = file.readAll();
        }
        _jsonTimer->start(30);
    }
}

void Widget::onCodeTimerTimeout()
{
    if (_codeIndex == _codeString.length()) {
        _codeEdit->clear();
        _codeIndex = 0;
        return;
    }
    QChar chr = _codeString.at(_codeIndex++);
    if (chr != '\r') {
        _codeEdit->insertPlainText(chr);
        _codeEdit->moveCursor(QTextCursor::End);
    }
}

void Widget::onJsonTimerTimeout()
{
    if (_jsonIndex == _jsonString.length()) {
        _jsonEdit->clear();
        _jsonIndex = 0;
        return;
    }
    QChar chr = _jsonString.at(_jsonIndex++);
    if (chr != '\r') {
        _jsonEdit->insertPlainText(chr);
        _jsonEdit->moveCursor(QTextCursor::End);
    }
}

void Widget::onDeviceTimerTimeout()
{
    QDateTime dateTime = QDateTime::currentDateTime();
    QString timeFormat = dateTime.toString("[yyyy-MM-dd hh:mm:ss] ");

    int temp = -10 + QRandomGenerator::global()->generate() % 50;  // -10~40°C
    int humi = 10 + QRandomGenerator::global()->generate() % 80;   // 0~90%

    QString tempDescription;
    if (temp <= -5) {
        tempDescription.append("(↓Lower) ");
    } else if (temp >= 35) {
        tempDescription.append("(↑Upper) ");
    } else {
        tempDescription.append("(Normal) ");
    }

    QString humiDescription;
    if (humi <= 15) {
        humiDescription.append("(↓Lower)");
    } else if (humi >= 85) {
        humiDescription.append("(↑Upper)");
    } else {
        humiDescription.append("(Normal)");
    }

    QString temperatureStr = QString("%1%2%3").arg("Temperature:").arg(temp, 3, 10).arg("°C " + tempDescription);
    QString humidityStr = QString("%1%2%3").arg("Humidity:").arg(humi, 3, 10).arg("% " + humiDescription);

    _deviceEdit->append(timeFormat + temperatureStr + humidityStr);
}
